package com.xzq.erp.filter;

import com.xzq.erp.constants.JwtConstants;
import com.xzq.erp.context.BaseContext;
import com.xzq.erp.domain.po.SysUser;
import com.xzq.erp.enums.ResponseCodeEnum;
import com.xzq.erp.mapper.SysUserMapper;
import com.xzq.erp.service.ISysUserService;
import com.xzq.erp.utils.JwtTool;
import com.xzq.erp.utils.Response;
import com.xzq.erp.utils.ResultUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Objects;

/**
 * JWT认证过滤器
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;
    private final JwtTool jwtTool;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        try{
            String requestURI = request.getRequestURI();

            // 从请求头中获取JWT令牌
            String requestHeader = request.getHeader(JwtConstants.AUTHORIZATION_HEADER);
            Long userId = null;
            String jwtToken = null;

            // 验证请求头中是否包含令牌
            if (requestHeader != null && requestHeader.startsWith(JwtConstants.TOKEN_PREFIX)) {
                jwtToken = requestHeader.substring(JwtConstants.TOKEN_PREFIX.length());

                try {
                    // 从令牌中提取用户名
                    userId = jwtTool.parseToken(jwtToken);
                    log.debug("从令牌中解析出用户ID: {}", userId);
                } catch (Exception e) {
                    log.error("无法从令牌中获取用户ID: {}", e.getMessage());
                }
            } else {
                log.debug("请求 {} 中未找到JWT令牌", requestURI);
            }

            // 验证令牌是否有效
            // JWT无效或没有 没有认证对象
            UserDetails userDetails = null;
            if (userId != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                //
                userDetails = userDetailsService.loadUserByUsername(String.valueOf(userId));
                if(Objects.nonNull(userDetails.getUsername())){
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities());
                    // 构建认证详情对象
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                    log.debug("用户 {} 通过JWT令牌认证成功", userId);
                }
                else{
                    log.debug("用户 {} 未找到", userId);
                    ResultUtil.fail(response, 401, Response.fail(ResponseCodeEnum.UNAUTHORIZED));
                }
            }
            else {
                log.debug("JWT令牌无效，不为用户 {} 设置安全上下文", userId);
            }
            // 手动校验ai请求
            if(requestURI.startsWith("/ai")){
                userDetails = userDetailsService.loadUserByUsername(String.valueOf(userId));
                if(Objects.isNull(userDetails.getUsername())){
                    // 返回Response对象
                    ResultUtil.fail(response, 401, Response.fail(ResponseCodeEnum.UNAUTHORIZED));
                    return;
                }
            }
            // 如果token校验失败 后面就没有认证对象 拦截器Context判断是否存在认证对象 没有直接抛出认证异常
            filterChain.doFilter(request, response);
        }
        finally {
            log.debug("JWT认证过滤器结束");
            BaseContext.removeUser();
        }
    }
} 